/*
 * 文件名：LayneGenerator.java
 * 版权：Copyright by layne
 * 描述：
 * 修改人：layne
 * 修改时间：2019年5月22日
 * 跟踪单号：
 * 修改单号：
 * 修改内容：
 */

package top.layne.boot.samples.generator.core;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.config.ConstVal;

import freemarker.template.Configuration;
import freemarker.template.Template;
import top.layne.boot.samples.generator.mybatis.MybatisPlusConfigBuilder;
import top.layne.boot.samples.generator.mybatis.MybatisPlusGenerator;

@Component
public class LayneGenerator implements CommandLineRunner {
	private static final Logger LOGGER = LoggerFactory.getLogger(LayneGenerator.class);

	@Resource
	private Environment environment;

	@Override
	public void run(String... args) throws Exception {
		LOGGER.debug("==========================LayneGenerator 准备生成文件...==========================");
		// 写入freemaker配置信息
		Map<String, Object> config = new HashMap<String, Object>();
		Map<String, Object> projectInfo = new HashMap<String, Object>();
		Map<String, String> packageInfo = new HashMap<String, String>();
		Map<String, String> datasource = new HashMap<String, String>();
		Map<String, String> tableInfo = new HashMap<String, String>();
		config.put("project", projectInfo);
		projectInfo.put("package", packageInfo);
		projectInfo.put("datasource", datasource);
		projectInfo.put("table", tableInfo);

		projectInfo.put("name", environment.getProperty("project.name"));
		projectInfo.put("port", environment.getProperty("project.port"));
		projectInfo.put("moduleName", environment.getProperty("project.moduleName"));
		projectInfo.put("outputDir", environment.getProperty("project.outputDir"));
		projectInfo.put("author", environment.getProperty("project.author"));
		projectInfo.put("swagger", Boolean.valueOf(environment.getProperty("project.swagger")));
		projectInfo.put("lombok", Boolean.valueOf(environment.getProperty("project.lombok")));

		packageInfo.put("base", environment.getProperty("project.package.base"));

		datasource.put("driverClassName", environment.getProperty("project.datasource.driver-class-name"));
		datasource.put("url", environment.getProperty("project.datasource.url"));
		datasource.put("username", environment.getProperty("project.datasource.username"));
		datasource.put("password", environment.getProperty("project.datasource.password"));

		tableInfo.put("include", environment.getProperty("project.table.include"));
		tableInfo.put("exclude", environment.getProperty("project.table.exclude"));

		// 注入mybatiplus配置信息
		MybatisPlusConfigBuilder configBuilder = new MybatisPlusConfigBuilder();
		configBuilder.setOutputDir(String.valueOf(projectInfo.get("outputDir")) + File.separator + String.valueOf(projectInfo.get("name")));
		configBuilder.setAuthor(String.valueOf(projectInfo.get("author")));
		configBuilder.setSwagger2(Boolean.valueOf(String.valueOf(projectInfo.get("swagger"))));
		configBuilder.setEntityLombokModel(Boolean.valueOf(String.valueOf(projectInfo.get("lombak"))));

		configBuilder.setExclude(StringUtils.isBlank(tableInfo.get("exclude")) ? null : tableInfo.get("exclude").split(","));
		configBuilder.setInclude(StringUtils.isBlank(tableInfo.get("include")) ? null : tableInfo.get("include").split(","));
		configBuilder.setModuleName(String.valueOf(projectInfo.get("moduleName")));
		configBuilder.setParent(String.valueOf(packageInfo.get("base")));

		configBuilder.setUrl(String.valueOf(datasource.get("url")));
		configBuilder.setDriverName(String.valueOf(datasource.get("driverClassName")));
		configBuilder.setUsername(String.valueOf(datasource.get("username")));
		configBuilder.setPassword(String.valueOf(datasource.get("password")));
		MybatisPlusGenerator plusGenerator = new MybatisPlusGenerator(configBuilder);
		plusGenerator.execute();

		// 开始根据模板生成文件信息
		Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
		configuration.setDefaultEncoding(ConstVal.UTF8);
		configuration.setClassForTemplateLoading(LayneGenerator.class, StringPool.SLASH);

		mkdirs(projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/java" + File.separator
				+ packageInfo.get("base").toString().replaceAll("\\.", StringPool.BACK_SLASH + File.separator) + File.separator + projectInfo.get("moduleName") + File.separator + "config");
		mkdirs(projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/java" + File.separator
				+ packageInfo.get("base").toString().replaceAll("\\.", StringPool.BACK_SLASH + File.separator) + File.separator + projectInfo.get("moduleName") + File.separator + "entity"
				+ File.separator + "base");
		mkdirs(projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/assembly");
		mkdirs(projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/resources");

		// 生成yml
		String ymlTemplatePath = "/templates/application.yml.ftl";
		Template ymlTemplate = configuration.getTemplate(ymlTemplatePath);
		String outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/resources" + File.separator + "application.yml";
		Writer writer = new OutputStreamWriter(new FileOutputStream(outputDir));
		ymlTemplate.process(config, writer);

		// 生成logback
		String logbackTemplatePath = "/templates/logback.xml.ftl";
		Template logbackTemplate = configuration.getTemplate(logbackTemplatePath);
		outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/resources" + File.separator + "logback.xml";
		writer = new OutputStreamWriter(new FileOutputStream(outputDir));
		logbackTemplate.process(config, writer);

		// 生成pom
		String pomTemplatePath = "/templates/pom.xml.ftl";
		Template pomTemplate = configuration.getTemplate(pomTemplatePath);
		outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "pom.xml";
		writer = new OutputStreamWriter(new FileOutputStream(outputDir));
		pomTemplate.process(config, writer);

		// 生成assembly
		String assemblyTemplatePath = "/templates/assembly.xml.ftl";
		Template assemblyTemplate = configuration.getTemplate(assemblyTemplatePath);
		outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/assembly" + File.separator + "assembly.xml";
		writer = new OutputStreamWriter(new FileOutputStream(outputDir));
		assemblyTemplate.process(config, writer);

		// 生成Application
		String applicationTemplatePath = "/templates/Application.java.ftl";
		Template applicationTemplate = configuration.getTemplate(applicationTemplatePath);
		outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/java" + File.separator
				+ packageInfo.get("base").toString().replaceAll("\\.", StringPool.BACK_SLASH + File.separator) + File.separator + projectInfo.get("moduleName") + File.separator + "Application.java";
		writer = new OutputStreamWriter(new FileOutputStream(outputDir));
		applicationTemplate.process(config, writer);

		// 生成mybatisplus-config
		String mybatisTemplatePath = "/templates/MyBatisPlusConfig.java.ftl";
		Template mybatisTemplate = configuration.getTemplate(mybatisTemplatePath);
		outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/java" + File.separator
				+ packageInfo.get("base").toString().replaceAll("\\.", StringPool.BACK_SLASH + File.separator) + File.separator + projectInfo.get("moduleName") + File.separator + "config"
				+ File.separator + "MyBatisPlusConfig.java";
		writer = new OutputStreamWriter(new FileOutputStream(outputDir));
		mybatisTemplate.process(config, writer);

		// 生成swagger-config
		if (configBuilder.isSwagger2()) {
			String swaggerTemplatePath = "/templates/SwaggerConfig.java.ftl";
			Template swaggerTemplate = configuration.getTemplate(swaggerTemplatePath);
			outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/java" + File.separator
					+ packageInfo.get("base").toString().replaceAll("\\.", StringPool.BACK_SLASH + File.separator) + File.separator + projectInfo.get("moduleName") + File.separator + "config"
					+ File.separator + "SwaggerConfig.java";
			writer = new OutputStreamWriter(new FileOutputStream(outputDir));
			swaggerTemplate.process(config, writer);
		}

		// 生成Message
		String messageTemplatePath = "/templates/Message.java.ftl";
		Template messageTemplate = configuration.getTemplate(messageTemplatePath);
		outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/java" + File.separator
				+ packageInfo.get("base").toString().replaceAll("\\.", StringPool.BACK_SLASH + File.separator) + File.separator + projectInfo.get("moduleName") + File.separator + "entity"
				+ File.separator + "base" + File.separator + "Message.java";
		writer = new OutputStreamWriter(new FileOutputStream(outputDir));
		messageTemplate.process(config, writer);

		// 生成DataGrid
		String dataGridTemplatePath = "/templates/DataGrid.java.ftl";
		Template dataGridTemplate = configuration.getTemplate(dataGridTemplatePath);
		outputDir = projectInfo.get("outputDir") + File.separator + projectInfo.get("name") + File.separator + "src/main/java" + File.separator
				+ packageInfo.get("base").toString().replaceAll("\\.", StringPool.BACK_SLASH + File.separator) + File.separator + projectInfo.get("moduleName") + File.separator + "entity"
				+ File.separator + "base" + File.separator + "DataGrid.java";
		writer = new OutputStreamWriter(new FileOutputStream(outputDir));
		dataGridTemplate.process(config, writer);

		LOGGER.debug("==========================LayneGenerator 文件生成完成！！！==========================");

	}

	public void mkdirs(String file) {
		File dir = new File(file);
		if (!dir.exists()) {
			boolean result = dir.mkdirs();
			if (result) {
				LOGGER.debug("创建目录： [" + file + "]");
			}
		}
	}

}
